package cn.stevenyang.services;

import cn.stevenyang.exceptions.VariableNotFoundException;
import cn.stevenyang.exceptions.VariablePathTooDeepException;

import java.util.HashMap;
import java.util.Stack;

public class MemoryService {
    private final HashMap<String, Object> variables = new HashMap<>();

    public HashMap<String, Object> getVariables() {
        return variables;
    }

    public void setVariable(String path, Object object) throws VariablePathTooDeepException {
        String[] pathArray = path.split("\\.");
        HashMap<String, Object> lastMap = getVariables();
        for (int i = 0; i < pathArray.length - 1; i++) {
            String currentBlock = pathArray[i];
            if (!lastMap.containsKey(currentBlock)) {
                lastMap.put(currentBlock, new HashMap<String, Object>());
            }
            HashMap<String, Object> tmpMap;
            try {
                tmpMap = (HashMap<String, Object>) lastMap.get(currentBlock);
            } catch (ClassCastException exception) {
                throw new VariablePathTooDeepException();
            }
            if (tmpMap != null) {
                lastMap = tmpMap;
            } else if (i == pathArray.length - 2) {
            } else {
                throw new VariablePathTooDeepException();
            }
        }
        lastMap.put(pathArray[pathArray.length - 1], object);
    }

    public Object getVariable(String path) throws VariableNotFoundException, VariablePathTooDeepException {
        String[] pathArray = path.split("\\.");
        HashMap<String, Object> lastMap = getVariables();
        for (int i = 0; i < pathArray.length - 1; i++) {
            String currentBlock = pathArray[i];
            if (!lastMap.containsKey(currentBlock)) {
                lastMap.put(currentBlock, new HashMap<String, Object>());
            }
            HashMap<String, Object> tmpMap;
            try {
                tmpMap = (HashMap<String, Object>) lastMap.get(currentBlock);
            } catch (ClassCastException exception) {
                throw new VariablePathTooDeepException();
            }
            if (tmpMap != null) {
                lastMap = tmpMap;
            } else if (i == pathArray.length - 2) {
            } else {
                throw new VariablePathTooDeepException();
            }
        }
        Object result;
        try {
            result = lastMap.get(pathArray[pathArray.length - 1]);
        } catch (Exception exception) {
            throw new VariableNotFoundException();
        }
        return result;
    }

    public Object getVariableOrNull(String path) {
        String[] pathArray = path.split("\\.");
        HashMap<String, Object> lastMap = getVariables();
        for (int i = 0; i < pathArray.length - 1; i++) {
            String currentBlock = pathArray[i];
            if (lastMap == null) {
                return null;
            }
            if (!lastMap.containsKey(currentBlock)) {
                lastMap.put(currentBlock, new HashMap<String, Object>());
            }
            try {
                lastMap = (HashMap<String, Object>) lastMap.get(currentBlock);
            } catch (ClassCastException exception) {
                return null;
            }
        }
        Object result;
        try {
            result = lastMap.get(pathArray[pathArray.length - 1]);
        } catch (Exception exception) {
            return null;
        }
        return result;
    }

    public Boolean hasDefinedVariable(String path) {
        String[] pathArray = path.split("\\.");
        HashMap<String, Object> lastMap = getVariables();
        for (int i = 0; i < pathArray.length - 1; i++) {
            String currentBlock = pathArray[i];
            if (!lastMap.containsKey(currentBlock)) {
                return false;
            }
            try {
                lastMap = (HashMap<String, Object>) lastMap.get(currentBlock);
            } catch (ClassCastException exception) {
                return false;
            }
        }
        return lastMap.containsKey(pathArray[pathArray.length - 1]);
    }

    public int lengthOfPath(String path) {
        String[] pathArray = path.split("\\.");
        return pathArray.length;
    }
}
